Skip to content

Make the RubyGems test suite green under RUBY_BOX=1 - #9826

Open
hsbt wants to merge 14 commits into
masterfrom
ruby-box-green-round1
Open

Make the RubyGems test suite green under RUBY_BOX=1#9826
hsbt wants to merge 14 commits into
masterfrom
ruby-box-green-round1

Conversation

@hsbt

@hsbt hsbt commented Aug 28, 2026

Copy link
Copy Markdown
Member

Running the test suite with RUBY_BOX=1 failed 38 tests and errored 18 on ruby master. This makes it green in both modes and adds a ruby-head lane so it stays that way.

The harness prepends -W:no-experimental to RUBYOPT for spawned processes, because every child ruby prints the Ruby::Box experimental warning to stderr and breaks assertions on subprocess output. Checks reading $? move to Process.last_status since Ruby::Box leaves it uninitialized, which also fixes Gem::Source::Git#rev_parse and the release tool swallowing failures at runtime. Tests that capture stdio or round-trip Gem:: constants through Marshal are pended under Ruby::Box only, each naming the ruby-core issue that has to land first.

The bundler spec harness gets the same treatment, and one blanket File.expand_path stub is scoped so it no longer defeats builtin Pathname.

Generated with Claude Code

@hsbt
hsbt force-pushed the ruby-box-green-round1 branch from bcc02be to 5f2d481 Compare August 31, 2026 08:38
@hsbt
hsbt force-pushed the ruby-box-green-round1 branch from 07fb452 to 72fa107 Compare September 9, 2026 10:50
hsbt and others added 14 commits September 9, 2026 20:05
Under RUBY_BOX=1 every spawned ruby prints an experimental warning to
stderr, which breaks tests asserting on subprocess output. Prepend
-W:no-experimental to RUBYOPT for child processes and add a
ruby_box_enabled? helper for box-specific guards.
Ruby::Box leaves $? uninitialized, so exit status checks read exit 0
regardless of the real status. Under RUBY_BOX=1 this made
Gem::Source::Git#rev_parse swallow git rev-parse failures, and made the
cargo availability pend in the test suite misjudge a broken toolchain as
usable. Process.last_status reports the real status in both modes.
Ruby::Box gives each box detached copies of the stdio globals, so
reassigning or reopening $stdout/$stderr cannot capture output written
by Kernel#warn, Kernel#puts or subprocesses, and $VERBOSE = nil cannot
silence category warnings in assert_ractor children. Pend the affected
tests until https://bugs.ruby-lang.org/issues/21867 is resolved.
Marshal in the main box cannot resolve Gem:: and other boxed constants,
so loading dumps of Gem::Specification, Gem::Version or Date raises
ArgumentError under RUBY_BOX=1. Pend the affected tests until
https://bugs.ruby-lang.org/issues/22090 is resolved.
The suite is green under RUBY_BOX=1 now, so run it on ruby-head as a
canary to catch regressions on either side early.
yamllint rejects the redundantly quoted matrix name. The cargo tests
require the installed gem with -r, which bypasses gem activation under
RUBY_BOX=1 because the command line require does not go through the
RubyGems Kernel#require override, so require inside -e instead.
Under RUBY_BOX every ruby subprocess spawned by the specs prints a
two-line experimental warning to stderr, breaking specs that assert
clean stderr. Strip those lines when the host ruby has boxes enabled,
instead of injecting -W:no-experimental into RUBYOPT, because several
specs assert the exact RUBYOPT propagated to subprocesses.
The special-characters and whitespace contexts stubbed File.expand_path
for every argument. Under RUBY_BOX=1 with the turbo_tests workers,
Bundler::Settings is still unloaded when these examples run, and reading
the repository .bundle/config triggers a lazy require of
rubygems/yaml_serializer. The default gem activation path in
Kernel#require then resolves paths through the stub and crashes with
Errno::ENOENT on a fake gemspec path. Stub only the expansion of
bundler/setup, which is all these examples need faked.
The example passes RUBYOPT=-rnative_child to the bundle install
subprocess, but under RUBY_BOX=1 require_libraries_in_main_box calls
rb_require_string directly and bypasses the RubyGems Kernel#require
override, so the gem is never activated and the require raises
LoadError. This is an unreported ruby-core bug related to [Bug #21760]
item 3, and the scenario itself is legitimate, so skip it until the
Ruby::Box require semantics are settled upstream.
The recursion is not in RbConfig.expand. Inside a box, defined?($gvar)
does not see assignments made in that box, so mkmf have_devel? never sees
its own memo and recurses until the stack is exhausted.
Both guards were written before the bugs had tickets. The $VERBOSE one
is now [Bug #22282] rather than a relative of [Bug #21867], and the
RUBYOPT -r one is [Bug #22295] rather than unreported.

Co-Authored-By: Claude Opus 5 <[email protected]>
The extension build note, the Process.last_status switch and the cargo
require were all written before their bugs had tickets. Each one now
names the issue that has to land before the workaround can go.

Co-Authored-By: Claude Opus 5 <[email protected]>
Both examples assert on stderr captured with capture_output, which comes
back empty under Ruby::Box. They landed with the ABI-scoped
specification support after this branch was written.

Co-Authored-By: Claude Opus 5 <[email protected]>
Ruby::Box leaves $? uninitialized, so the three probes read a successful
status after a failing command and carry an empty ref date into
Time.xmlschema, which raises instead of the intended error.

Co-Authored-By: Claude Opus 5 <[email protected]>
@hsbt
hsbt force-pushed the ruby-box-green-round1 branch from 72fa107 to 35619ee Compare September 9, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant